{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Conversation with Software Engineering Agent\n",
    "\n",
    "SWE-agent(SoftWare Engineering Agent) is an agent designed for solving real world software engineering problems, such as fixing github issues.\n",
    "More details can be found in the project's [homepage](https://swe-agent.com/) and related [github repo](https://swe-agent.com/).\n",
    "\n",
    "In the example here, we partially implement the SWE-agent, and provide a simple example of how to use the implemented SWE-agent to fix a bug in a python file.\n",
    "You should note that currently how to enable agents with stronger programming capabilities remains an open challenge, and the performance of the paritially implemented SWE-agent is not guaranteed.\n",
    "\n",
    "## Prerequisites\n",
    "\n",
    "- Follow [READMD.md](https://github.com/modelscope/agentscope) to install AgentScope. We require the lastest version, so you should build from source by running `pip install -e .` instead of intalling from pypi. \n",
    "- Prepare a model configuration. AgentScope supports both local deployed model services (CPU or GPU) and third-party services. More details and example model configurations please refer to our [tutorial](https://modelscope.github.io/agentscope/en/tutorial/203-model.html).\n",
    "- Understand the ServiceToolkit module and how to use it to pre-process the tool functions for LLMs. You can refer to the [ReAct agent example](../conversation_with_react_agent/main.ipynb) and you should also refer to the [tutorial](https://modelscope.github.io/agentscope/en/tutorial/204-service.html) for service functions.\n",
    "\n",
    "\n",
    "## Note\n",
    "\n",
    "- The example is tested with the following models. For other models, you may need to adjust the prompt.\n",
    "    - gpt-4\n",
    "    - dashscope_chat (qwen-max)\n",
    "    - gemini_chat (gemini-pro)\n",
    "    - ollama_chat (llama3_8b)\n",
    "- How to enable agents with stronger programming capabilities remains an open challenge, and the current implementations are not perfect. Please feel free to explore it yourself."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "YOUR_MODEL_CONFIGURATION_NAME = \"{YOUR_MODEL_CONFIGURATION_NAME}\"\n",
    "\n",
    "YOUR_MODEL_CONFIGURATION = {\n",
    "    \"model_type\": \"xxx\", \n",
    "    \"config_name\": YOUR_MODEL_CONFIGURATION_NAME\n",
    "    \n",
    "    # ...\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 1: Initialize the AgentScope environment and SWE-agent\n",
    "\n",
    "Here we init the agentscope environment and load the SWE-agent.\n",
    "\n",
    "The code of SWE-agent is in `swe_agent.py`, and the related prompts are in `swe_agent_prompts.py`.\n",
    "\n",
    "If you are interested in the details, please refer to the code and the origianl SWE-agent repo [here](https://github.com/princeton-nlp/SWE-agent)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from swe_agent import SWEAgent\n",
    "\n",
    "import agentscope\n",
    "\n",
    "agentscope.init(\n",
    "    model_configs=YOUR_MODEL_CONFIGURATION,\n",
    "    project=\"Conversation with SWE-agent\",\n",
    ")\n",
    "\n",
    "agent = SWEAgent(\n",
    "    name=\"assistant\",\n",
    "    model_config_name=YOUR_MODEL_CONFIGURATION_NAME,\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 2: Create the code to be processed by the SWE-agent\n",
    "\n",
    "Here we use the `write_file` function to write the following code into `gcd.py`.\n",
    "The code here is a wrong implementation of the [Greatest Common Divisor (GCD) algorithm](https://en.wikipedia.org/wiki/Euclidean_algorithm).\n",
    "We will ask the SWE-agent to correct it in our next step."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'status': <ServiceExecStatus.SUCCESS: 1>,\n",
       " 'content': 'WRITE OPERATION:\\nYou have written to \"gcd.py\"                 on these lines: 0:-1.\\ndef gcd(a, b):\\n    if a == 0:\\n        return b\\n    while a != 0:\\n        a, b = b, a\\n    return b\\n\\ndef lcm(a, b):\\n    return (a * b) // gcd(a, b)\\n\\n# testing on GCD and LCM functions\\nprint(\"GCD of 12 and 18 is:\", gcd(12, 18))\\nprint(\"LCM of 12 and 18 is:\", lcm(12, 18))\\n\\n'}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from swe_agent_service_func import write_file\n",
    "\n",
    "# here the gcd code is written in a wrong way\n",
    "wrong_gcd_text = \"\"\"\n",
    "def gcd(a, b):\n",
    "    if a == 0:\n",
    "        return b\n",
    "    while a != 0:\n",
    "        a, b = b, a\n",
    "    return b\n",
    "\n",
    "def lcm(a, b):\n",
    "    return (a * b) // gcd(a, b)\n",
    "\n",
    "# testing on GCD and LCM functions\n",
    "print(\"GCD of 12 and 18 is:\", gcd(12, 18))\n",
    "print(\"LCM of 12 and 18 is:\", lcm(12, 18))\n",
    "\"\"\"\n",
    "\n",
    "write_file(\"gcd.py\", wrong_gcd_text)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3: Ask the SWE-agent to correct the code\n",
    "\n",
    "Here we simple ask the SWE-agent to correct the code in `gcd.py`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "user: The file in gcd.py is not returning the correct answer, can you fix the file for me?\n",
      "assistant: {\n",
      "    \"thought\": \"First thing I'll do is read the content of gcd.py file to understand the existing logic.\",\n",
      "    \"action\": {\n",
      "        \"name\": \"read_file\",\n",
      "        \"arguments\": {\n",
      "            \"file_path\": \"gcd.py\"\n",
      "        }\n",
      "    }\n",
      "}\n",
      "assistant: \n",
      "====Observation====\n",
      "\n",
      "def gcd(a, b):\n",
      "    if a == 0:\n",
      "        return b\n",
      "    while a != 0:\n",
      "        a, b = b, a\n",
      "    return b\n",
      "\n",
      "def lcm(a, b):\n",
      "    return (a * b) // gcd(a, b)\n",
      "\n",
      "# testing on GCD and LCM functions\n",
      "print(\"GCD of 12 and 18 is:\", gcd(12, 18))\n",
      "print(\"LCM of 12 and 18 is:\", lcm(12, 18))\n",
      "\n",
      "\n",
      "assistant: {\n",
      "    \"thought\": \"I can see the error in the gcd calculation. The gcd calculation in the file is incorrect. The correct way to find the gcd of two numbers using the Euclidean algorithm is to continually reduce a and b by finding the remainder of a % b until b is 0, at which point a will be the gcd of the original a and b values. In the given code, instead of finding the remainder, it is incorrectly swapping the values of a and b. I'll correct this error by modifying the gcd function using the write_file command, reflecting the correct Euclidean algorithm.\",\n",
      "    \"action\": {\n",
      "        \"name\": \"write_file\",\n",
      "        \"arguments\": {\n",
      "            \"start_line\": 0,\n",
      "            \"end_line\": 15,\n",
      "            \"content\": \"def gcd(a, b):\\n    while b != 0:\\n        a, b = b, a % b\\n    return a\\n\\n\\ndef lcm(a, b):\\n    return (a * b) // gcd(a, b)\\n\\n\\n# testing on GCD and LCM functions\\nprint(\\\"GCD of 12 and 18 is:\\\", gcd(12, 18))\\nprint(\\\"LCM of 12 and 18 is:\\\", lcm(12, 18))\\n\",\n",
      "            \"file_path\": \"gcd.py\"\n",
      "        }\n",
      "    }\n",
      "}\n",
      "assistant: \n",
      "====Observation====\n",
      "WRITE OPERATION:\n",
      "You have written to \"gcd.py\"                 on these lines: 0:15.def gcd(a, b):\n",
      "    while b != 0:\n",
      "        a, b = b, a % b\n",
      "    return a\n",
      "\n",
      "\n",
      "def lcm(a, b):\n",
      "    return (a * b) // gcd(a, b)\n",
      "\n",
      "\n",
      "# testing on GCD and LCM functions\n",
      "print(\"GCD of 12 and 18 is:\", gcd(12, 18))\n",
      "print(\"LCM of 12 and 18 is:\", lcm(12, 18))\n",
      "\n",
      "\n",
      "assistant: {\n",
      "    \"thought\": \"I should run the python file to see if the changes I made have fixed the gcd function.\",\n",
      "    \"action\": {\n",
      "        \"name\": \"execute_shell_command\",\n",
      "        \"arguments\": {\n",
      "            \"command\": \"python3 gcd.py\"\n",
      "        }\n",
      "    }\n",
      "}\n",
      "assistant: \n",
      "====Observation====\n",
      "GCD of 12 and 18 is: 6\n",
      "LCM of 12 and 18 is: 36\n",
      "assistant: {\n",
      "    \"thought\": \"The gcd.py file has been fixed and tested successfully. Therefore, no further actions are needed.\",\n",
      "    \"action\": {\n",
      "        \"name\": \"exit\",\n",
      "        \"arguments\": {}\n",
      "    }\n",
      "}\n",
      "assistant: \n",
      "====Observation====\n",
      "Current task finished, exitting.\n"
     ]
    }
   ],
   "source": [
    "from loguru import logger\n",
    "from agentscope.message import Msg\n",
    "\n",
    "mss = Msg(\n",
    "    name=\"user\", \n",
    "    content=\"The file in gcd.py is not returning the correct answer, can you fix the file for me?\", \n",
    "    role=\"user\"\n",
    ")\n",
    "logger.chat(mss)\n",
    "answer_mss = agent(mss)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Conlusion\n",
    "\n",
    "After a few iterations, the SWE-agent assistant finish the job successfully, and the code is now working fine."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Above we shown a example of how to use the SWE-agent to fix code errors.\n",
    "Although the design of the SWE-agent is primarily aimed at addressing GitHub issues, with modifications, it can also be utilized for more general programming tasks.\n",
    "\n",
    "Currently, how to enable agent with general programming ablities remains a challenging open question, with the efficacy of agent programming potentially influenced by factors such as prompt construction, model capabilities, and the complexity of the task at hand. Here we just provide an interesting toy example. \n",
    "\n",
    "We encourage users to experiment by altering the prompts within this example or by assigning different tasks to the agent, among other methods of exploration. Please feel free to experiment and explore on your own. The AgentScope team will continue to provide updates, enhancing the capabilities of the Programming Agents in the future!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "datajuicer",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
